package com.dctp.ems.controller;

import com.alibaba.fastjson.JSON;
import com.dctp.common.cache.ContractCache;
import com.dctp.common.cache.FuturesCache;
import com.dctp.common.cache.UserCache;
import com.dctp.common.controller.BaseController;
import com.dctp.common.core.RedisManager;
import com.dctp.common.db.UserDb;
import com.dctp.common.disruptor.close.CloseOrder;
import com.dctp.common.disruptor.close.CloseOrderDisruptor;
import com.dctp.common.service.TradeService;
import com.dctp.common.utils.CollectUtil;
import com.dctp.common.utils.DateUtil;
import com.dctp.common.utils.StringUtil;
import com.dctp.common.vo.*;
import com.jfinal.aop.Before;
import com.jfinal.core.NotAction;
import com.jfinal.core.Path;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.tx.Tx;

import java.util.*;
import java.util.concurrent.Executors;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.stream.Collectors;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;

@Path("/tradeOrder")
public class TradeOrderController extends BaseController {

    private static final Logger logger = LoggerFactory.getLogger(TradeOrderController.class.getName());
    /**
     * GET /tradeOrder/list
     * 分页查询交易订单，支持user_id、contract_id、status、open_time范围
     */
    public void list() {
        int page = getInt("currentPage", 1);
        int pageSize = getInt("pageSize", 10);

        QueryResult qr = buildTradeOrderQuery();
        String select = "SELECT * ";
        String from = "FROM dctp_order" + qr.where + " ORDER BY id DESC";
        var p = Db.paginate(page, pageSize, select, from, qr.params.toArray());
        List<Record> list = p.getList();

        List<Long> orderIdList = new ArrayList<>();
        for (Record r : list) {

            r.set("contract_name", ContractCache.getName(r.getLong("contract_id")));
            r.set("user",UserCache.getBasic(r.getLong("user_id")));
            r.set("open_time", DateUtil.toLocalDateTime(r.getLong("open_time")));
            orderIdList.add(r.getLong("id"));
            String key = getGroupByIdKey();
            Long orgId = r.getLong(key);
            if (null != orgId) {
                Record showInfo = UserCache.getShowInfo(orgId);
                r.set("orgInfo", showInfo);
            }
        }

        Integer status = getInt("status");
        if (null != status && status == 1) {
            if (CollectUtil.isNotEmpty(orderIdList)) {
                Map<String, Object> payload = new HashMap<>();
                payload.put("adminId",getRequestUser().getLong("id"));
                payload.put("type", "1"); // 持仓中
                payload.put("orderIds", orderIdList); // List<Long>，会被 JSON 自动序列化为数组
                RedisManager.getInstance().publish(
                        RedisKey.PUB_SUB_ADMIN_ORDER,
                        JSON.toJSONString(payload)
                );
            }
        }
        renderJson(JsonResult.successWithData(
            new PageResult<>(list, p.getTotalRow(), pageSize, page)
        ));
    }


    /**
     * GET /tradeOrder/groupStat
     * 按 user_id、symbol 分组统计总手数、总服务费、总平仓盈亏（仅统计已平仓 status=2 的记录），支持 user_id/symbol/时间范围/分页查询
     */
    public void groupStat() {

        long begin = System.currentTimeMillis();
        int page = getInt("currentPage", 1);
        int pageSize = getInt("pageSize", 10);

        // 查询参数
        Long userId = getParaToLong("user_id");
        String symbol = getPara("symbol");
        String startTime = getPara("start_time");
        String endTime = getPara("end_time");

        // 构建 where 子句
        StringBuilder where = new StringBuilder(" WHERE status = 2 ");
        List<Object> params = new ArrayList<>();

        if (userId != null) {
            where.append(" AND user_id = ?");
            params.add(userId);
        }
        if (StringUtil.isNotEmpty(symbol)) {
            where.append(" AND symbol = ?");
            params.add(symbol);
        }
        if (StringUtil.isNotEmpty(startTime)) {
            where.append(" AND close_time >= ?");
            params.add(startTime);
        }
        if (StringUtil.isNotEmpty(endTime)) {
            where.append(" AND close_time <= ?");
            params.add(endTime);
        }


        String filterField = getFilterField();
        Long filterUserId = getRequestUser().getLong("user_id");
        if (filterField != null && filterUserId != null) {
            where.append(" AND ").append(filterField).append(" = ?");
            params.add(filterUserId);
        }

        String roleKey = getPara("roleKey");
        Long roleUserId = getParaToLong("roleUserId");
        if (StringUtil.isNotEmpty(roleKey) && null != roleUserId) {
            where.append(" AND ").append(roleKey).append(" = ? ");
            params.add(roleUserId);
        }


        // 分组统计 SQL，加上分组的开始/结束时间
        String select = "SELECT user_id, symbol, " +
                "SUM(quantity) AS total_quantity, " +
                "SUM(realized_pnl) AS total_realized_pnl, " +
                "SUM(open_service_fee + close_service_fee) AS total_service_fee, " +
                "MIN(create_time) AS start_time, MAX(close_time) AS end_time ";

        String from = "FROM dctp_order " + where + " GROUP BY user_id, symbol ORDER BY end_time DESC ";
        var pageData = Db.paginate(page, pageSize, select, from, params.toArray());

        if (CollectUtil.isNotEmpty(pageData.getList())) {
            for (Record r : pageData.getList()) {
                r.set("contract_name", ContractCache.getNameBySymbol(r.getStr("symbol")));
                Long uid = r.getLong("user_id");
                Record user = UserCache.getBasic(uid);
                r.set("start_time", DateUtil.format(r.getLocalDateTime("start_time"),"MM-dd HH:mm"));
                r.set("end_time", DateUtil.format(r.getLocalDateTime("end_time"),"MM-dd HH:mm"));
                if (null != user) {
                    r.set("user",UserCache.getShowInfo(uid));
                    String key = getGroupByIdKey();
                    Long orgId = user.getLong(key);
                    if (null != orgId) {
                        Record showInfo = UserCache.getShowInfo(orgId);
                        r.set("orgInfo", showInfo);
                    }
                }
            }
        }
        long end = System.currentTimeMillis();
        logger.info("take time:" + (end - begin));
        renderJson(JsonResult.successWithData(
                new PageResult<>(pageData.getList(), pageData.getTotalRow(), pageSize, page)
        ));
    }


    /**
     * GET /tradeOrder/export
     * 导出交易订单Excel，支持user_id、contract_id、status、open_time范围
     */
    public void export() {
        int pageSize = 10000; // 导出最大行数
        QueryResult qr = buildTradeOrderQuery();
        String sql = "SELECT * FROM dctp_order" + qr.where + " ORDER BY id DESC LIMIT ?";
        qr.params.add(pageSize);
        List<Record> list = Db.find(sql, qr.params.toArray());
        for (Record r : list) {
            Long openTime = r.getLong("open_time");
            if (openTime != null) {
                // open_time 是时间戳（秒或毫秒），需转为字符串
                String openTimeStr = null;
                if (openTime > 1000000000000L) { // 毫秒
                    openTimeStr = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date(openTime));
                } else { // 秒
                    openTimeStr = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date(openTime * 1000));
                }
                r.set("open_time_str", openTimeStr);
            }
            LocalDateTime closeTime = r.getLocalDateTime("close_time");
            if (closeTime != null) {
                r.set("close_time", DateUtil.format(closeTime, "yyyy-MM-dd HH:mm:ss"));
            }
        }
        try (Workbook wb = new XSSFWorkbook()) {
            Sheet sheet = wb.createSheet("交易订单");
            // 表头
            String[] fields = {"id", "user_id", "contract_id", "futures_id", "direction", "order_source", "quantity", "open_price", "take_profit_price", "stop_loss_price", "open_time_str", "margin_occupied", "open_service_fee", "floating_pnl", "close_price", "close_quantity", "close_time", "close_service_fee", "realized_pnl", "status", "create_time", "update_time", "close_type", "symbol"};
            String[] titles = {"ID", "用户ID", "合约ID", "品种ID", "方向", "来源", "手数", "开仓价", "止盈价", "止损价", "开仓时间", "占用保证金", "开仓手续费", "浮动盈亏", "平仓价", "已平手数", "平仓时间", "平仓手续费", "已实现盈亏", "状态", "创建时间", "更新时间", "平仓类型", "合约代码"};
            Row head = sheet.createRow(0);
            for (int i = 0; i < titles.length; i++) {
                head.createCell(i).setCellValue(titles[i]);
            }
            // 数据
            int rowIdx = 1;
            for (Record r : list) {
                Row row = sheet.createRow(rowIdx++);
                for (int i = 0; i < fields.length; i++) {
                    Object val = r.get(fields[i]);
                    if (val == null) {
                        row.createCell(i).setCellValue("");
                    } else if (val instanceof Number) {
                        row.createCell(i).setCellValue(((Number) val).toString());
                    } else {
                        row.createCell(i).setCellValue(val.toString());
                    }
                }
            }
            // 响应下载
            HttpServletResponse resp = getResponse();
            String fileName = "trade_order_" + DateUtil.format(DateUtil.now(), "yyyyMMddHHmmss") + ".xlsx";
            resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            resp.setHeader("Content-Disposition", "attachment; filename=" + fileName);
            wb.write(resp.getOutputStream());
            renderNull();
        } catch (Exception e) {
            renderJson(JsonResult.failWithMessage("导出失败: " + e.getMessage()));
        }
    }

    @Before(Tx.class)
    public void compensate() {

        Long activiyId = getParaToLong("activity_id");
        Record activity = Db.findFirst("SELECT * FROM dctp_activity WHERE id = ?", activiyId);
        if (activity == null) {
            renderJson(JsonResult.failWithMessage("活动不存在或已被删除"));
            return;
        }

        LocalTime activityBeginTime = LocalTime.parse(activity.getStr("begin_time"));
        LocalTime activityEndTime = LocalTime.parse(activity.getStr("end_time"));

        LocalDateTime beginDateTime = LocalDateTime.of(LocalDate.now(), activityBeginTime);
        LocalDateTime endDateTime = LocalDateTime.of(LocalDate.now(), activityEndTime);

        List<Record> orders = Db.find("SELECT id,user_id,abs(realized_pnl) as realized_pnl  FROM dctp_order WHERE status = 2 and realized_pnl < 0 and compensate = 0 AND open_time >= ? AND open_time <= ?", 
            DateUtil.toEpochMilli(beginDateTime), DateUtil.toEpochMilli(endDateTime));
        if (CollectUtil.isEmpty(orders)) {
            renderJson(JsonResult.failWithMessage("没有需要赔付的订单"));
            return;
        }

        if (orders.size() > 200) {
            // 如果订单数量超过500，直接返回处理中的状态
            renderJson(JsonResult.successWithData("processing"));
            Executors.newSingleThreadExecutor().submit((Runnable) () -> {
                Db.tx(() -> {
                    // 在新线程中处理赔付逻辑
                    try {
                        this.handleCompensate(orders, activiyId, beginDateTime, endDateTime);
                        return true;
                    } catch (Exception e) {
                        logger.error("Compensate failed", e);
                        return false;
                    }
                });
            });
            return;
        }
       this.handleCompensate(orders, activiyId, beginDateTime, endDateTime);
       renderJson(JsonResult.success());
    }


    @Before(Tx.class)
    public void compensateOrder() {

        Long id = getParaToLong(0);
        if (id == null) {
            renderJson(JsonResult.failWithMessage("参数缺失"));
            return;
        }

        Record order = Db.findById("dctp_order", id);
        if (order == null) {
            renderJson(JsonResult.failWithMessage("订单不存在"));
            return;
        }
        if (order.getInt("status") != 2 || order.getInt("compensate") != 0) {
            renderJson(JsonResult.failWithMessage("订单状态不符合赔付条件"));
            return;
        }
        Record body = jsonBody();
        BigDecimal realizedPnl = body.getBigDecimal("realized_pnl");
        if (realizedPnl == null || realizedPnl.compareTo(BigDecimal.ZERO) <= 0) {
            renderJson(JsonResult.failWithMessage("赔付金额无效"));
            return;
        }
        this.handleSingle(order, id, realizedPnl);
        int r = Db.update("UPDATE dctp_order SET compensate = 1, compensate_amount = ?, update_time = now() WHERE id = ?",
            realizedPnl, id);
        if (r != 1) {
            throw new RuntimeException("Failed to update order compensate status for order: " + id);
        }
        renderJson(JsonResult.success());
    }


    @NotAction
    private void handleSingle(Record order, Long id, BigDecimal compensateAmount) {

        Long userId = order.getLong("user_id");
        // 检查用户是否存在
        Record user = UserDb.findBasicById(userId);
        if (user == null) {
            throw new RuntimeException("User not found: " + userId);
        }
        // 更新用户余额
        int r = Db.update("UPDATE dctp_user SET balance = balance + ? WHERE id = ? ", compensateAmount, userId);
        if (r != 1) {
            throw new RuntimeException("Failed to update user balance for user: " + userId);
        }
        // 记录赔付记录
        BigDecimal balance = user.getBigDecimal("balance");

        Long parentId = user.getLong("parent_id");
        Long bottomRoleUserId = user.getLong("bottom_role_user_id");
        Long middleRoleUserId = user.getLong("middle_role_user_id");
        Long topRoleUserId = user.getLong("top_role_user_id");

        LocalDateTime now = DateUtil.now();
        Record fundFlowRecord = new Record()
            .set("user_id", userId)
            .set("balance_before", balance)
            .set("change_amount", compensateAmount)
            .set("balance_after", balance.add(compensateAmount))
            .set("change_type", FundChangeType.COMEPENSATE.getCode())
            .set("description", "补仓，订单ID:" + id)
            .set("remark", "补偿")
            .set("parent_id", parentId)
            .set("bottom_role_user_id", bottomRoleUserId)
            .set("middle_role_user_id", middleRoleUserId)
            .set("top_role_user_id", topRoleUserId)
            .set("create_time", now)
            .set("update_time", now);
        if (!Db.save("dctp_fund_flow", fundFlowRecord)) {
            throw new RuntimeException("Failed to save fund flow for user: " + userId);
        }
    }

    @NotAction
    private void handleCompensate(List<Record> orders, Long activityId, LocalDateTime beginDateTime, LocalDateTime endDateTime) {

         for (Record order : orders) {
           this.handleSingle(order, activityId, order.getBigDecimal("realized_pnl"));
        }
        // 更新订单状态
        Db.update("UPDATE dctp_order SET compensate = 1, compensate_amount = abs(realized_pnl),update_time = now() where status = 2 AND compensate = 0 AND " + 
        " open_time >= ? AND open_time <= ? ",DateUtil.toEpochMilli(beginDateTime), DateUtil.toEpochMilli(endDateTime));
    }

    private QueryResult buildTradeOrderQuery() {
        Long userId = getParaToLong("user_id");
        Long contractId = getParaToLong("contract_id");
        Integer status = getParaToInt("status", null);
        String startTime = getPara("start_time");
        String endTime = getPara("end_time");
        StringBuilder where = new StringBuilder(" WHERE 1=1 ");
        List<Object> params = new ArrayList<>();
        if (userId != null) {
            where.append(" AND user_id = ?");
            params.add(userId);
        }
        if (contractId != null) {
            where.append(" AND contract_id = ?");
            params.add(contractId);
        }

        String symbol = getPara("symbol");
        if (StringUtil.isNotEmpty(symbol)) {
            where.append(" AND symbol = ?");
            params.add(symbol);
        }

        Integer direction = getParaToInt("direction");
        if (null != direction) {
            where.append(" AND direction = ?");
            params.add(direction);
        }

        Integer orderType = getParaToInt("order_type");
        if (null != orderType) {
            where.append(" AND order_type = ?");
            params.add(orderType);
        }

        if (status != null) {

            if (status == 99) {
                //止盈止损
                where.append(" AND (take_profit_price > 0 OR stop_loss_price > 0)");
            }else if (status == 98) {
                //成交
                where.append(" AND status in (1,2) ");
            }else {
                where.append(" AND status = ?");
                params.add(status);
            }
        }
        if (startTime != null && !startTime.isEmpty()) {
            where.append(" AND open_time >= ?");
            params.add(DateUtil.toEpochMilli(DateUtil.parse(startTime)));
        }
        if (endTime != null && !endTime.isEmpty()) {
            where.append(" AND open_time <= ?");
            params.add(DateUtil.toEpochMilli(DateUtil.parse(endTime)));
        }


        String closeStartTime = getPara("close_start_time");
        String closeEndTime = getPara("close_end_time");
        if (StringUtil.isNotEmpty(closeStartTime)) {
            where.append(" AND close_time >= ?");
            params.add(closeStartTime);
        }

        if (StringUtil.isNotEmpty(closeEndTime)) {
            where.append(" AND close_time <= ?");
            params.add(closeEndTime);
        }

        Integer activityId = getParaToInt("activity_id");
        if (activityId != null && activityId > 0) {
            
            Record activity = Db.findFirst("SELECT * FROM dctp_activity WHERE id = ?", activityId);
            if (null != activity) {
                // 活动存在
                LocalTime activityBeginTime = LocalTime.parse(activity.getStr("begin_time"));
                LocalTime activityEndTime = LocalTime.parse(activity.getStr("end_time"));

                LocalDateTime beginDateTime = LocalDateTime.of(LocalDate.now(), activityBeginTime);
                LocalDateTime endDateTime = LocalDateTime.of(LocalDate.now(), activityEndTime);
                where.append(" AND close_time >= ? and close_time <= ? ");
                params.add(DateUtil.toEpochMilli(beginDateTime));
                params.add(DateUtil.toEpochMilli(endDateTime));
            }
        }

        String realizedPnlFlag = getPara("realized_pnl_flag");
        if (StringUtil.isNotEmpty(realizedPnlFlag)) {
            Integer rpf = Integer.parseInt(realizedPnlFlag);
            if (rpf > 0) {
                where.append(" AND realized_pnl >= 0 ");
            } else if (rpf < 0) {
                where.append(" AND realized_pnl < 0 ");
            }
        }

        Integer compensate = getParaToInt("compensate");
        if (compensate != null) {
            where.append(" AND compensate = ? ");
            params.add(compensate);
        }
        
        //委托单
//        Integer orderType = getParaToInt("order_type");
//        if (orderType != null && orderType > 0) {
//            where.append(" AND order_type = ? AND status < 2 ");//挂单中，加载成交和未成交的
//            params.add(orderType);
//        }

        String filterField = getFilterField();
        Long filterUserId = getRequestUser().getLong("user_id");
        if (filterField != null && filterUserId != null) {
            where.append(" AND ").append(filterField).append(" = ? ");
            params.add(filterUserId);
        }

        String roleKey = getPara("roleKey");
        Long roleUserId = getParaToLong("roleUserId");
        if (StringUtil.isNotEmpty(roleKey) && null != roleUserId) {
            where.append(" AND ").append(roleKey).append(" = ?");
            params.add(roleUserId);
        }

        return new QueryResult(where, params);
    }

    @Before(Tx.class)
    public void batchClose() {
        Record body = jsonBody();
        String ids = body.getStr("ids");
        if (StringUtil.isEmpty(ids)) {
            renderJson(JsonResult.failWithMessage("请选择要平仓的订单"));
            return;
        }

        // 分割成数组
        String[] idArr = ids.split(",");
        // 构建占位符 ?,?,?
        String placeholders = String.join(",", java.util.Collections.nCopies(idArr.length, "?"));

        List<Record> orders = Db.find("SELECT * FROM dctp_order WHERE id IN (" + placeholders + ")", (Object[]) idArr);
        if (CollectUtil.isEmpty(orders)) {
            renderJson(JsonResult.failWithMessage("订单不存在"));
            return;
        }

        for (Record order : orders) {
            BigDecimal closePrice = ContractCache.getLastPriceBySymbol(order.getStr("symbol"));
            if (closePrice == null || closePrice.compareTo(BigDecimal.ZERO) <= 0) {
                continue;
            }
            Record user = UserDb.findBasicById(order.getLong("user_id"));
            CloseOrder closeOrder = TradeService.handleCloseOrder(order,user,closePrice,order.getInt("quantity"),OrderDealType.EMS_DEAL.getCode());
            CloseOrderDisruptor.publish(closeOrder);
        }
        renderJson(JsonResult.success());
    }
}
